package com.zhou.common.mybatis.template.shiro.zhou.config;

import com.zhou.common.mybatis.template.shiro.zhou.filter.TraceFilter;
import com.zhou.common.mybatis.template.shiro.zhou.filter.UserCenterLoginConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;

import javax.sql.DataSource;



@EnableWebSecurity
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Bean
    public FilterRegistrationBean traceFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new TraceFilter());
        registration.addUrlPatterns("/*");
        registration.setName("traceFilter");
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registration;
    }


    public SwitchUserFilter switchUserFilter(UserDetailsService userDetailsService) throws Exception {
        SwitchUserFilter switchUserFilter = new SwitchUserFilter();
        switchUserFilter.setUserDetailsService(userDetailsService);
        switchUserFilter.setTargetUrl("/session");
        return switchUserFilter;
    }


    @Autowired
    private FindByIndexNameSessionRepository findByIndexNameSessionRepository;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //Each <http> namespace block always creates an SecurityContextPersistenceFilter, an ExceptionTranslationFilter and a FilterSecurityInterceptor. These are fixed and cannot be replaced with alternatives.
        http
//                .regexMatcher("/test")
                .addFilterAfter(switchUserFilter(userDetailsService()), FilterSecurityInterceptor.class)
                //.exceptionHandling().authenticationEntryPoint(new UnauthorizedEntryPoint())
                //.and()
/*                .apply(new UserCenterLoginConfigurer())
                .and()*/
                .apply(new UserCenterLoginConfigurer<HttpSecurity>())
                .and()
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/login/**", "/css/**", "/js/**", "/fonts/**").permitAll()
                .antMatchers("/session").authenticated()
                .antMatchers("/login/impersonate").hasAuthority("ROLE_ADMIN")
                .antMatchers("/logout/impersonate").hasAuthority(SwitchUserFilter.ROLE_PREVIOUS_ADMINISTRATOR)
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .defaultSuccessUrl("/test2")

                .and()
                .logout()
                .deleteCookies("JSESSIONID")
                .and()
                //后面的session替换掉原来的session
                //.expiredSessionStrategy() 过期的策略，是重定向，还是直接给出文字提示
                //maxSessionsPreventsLogin() 超过最大的session 阻止登录
                //默认是最早的被覆盖掉
                .sessionManagement().maximumSessions(2).maxSessionsPreventsLogin(true).sessionRegistry(sessionRegistry())
                .and()
        ;
    }

    @Bean
    public UserDetailsManager users(DataSource dataSource) {
/*        UserDetails user = User.builder()
                .username("user")
                .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
                .roles("USER")
                .build();
        UserDetails admin = User.builder()
                .username("admin")
                .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
                .roles( "ADMIN")
                .build();*/
        JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
/*        users.createUser(user);
        users.createUser(admin);*/
        return users;
    }


    /**
     * 角色继承配置
     *  可以在数据库初始化，然后代码加载
     * @return
     */
    @Bean
    public RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_DBA \n" +
                "ROLE_DBA > ROLE_USER");
        return roleHierarchy;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
    }


    @Bean
    public SpringSessionBackedSessionRegistry sessionRegistry() {
        return new SpringSessionBackedSessionRegistry<>(this.findByIndexNameSessionRepository);
    }

    @Bean
    public SpringSessionRememberMeServices rememberMeServices() {
        SpringSessionRememberMeServices rememberMeServices =
                new SpringSessionRememberMeServices();
        // optionally customize
        rememberMeServices.setAlwaysRemember(true);
        return rememberMeServices;
    }
}